import * as step from '@flow-step/step-toolkit'
import {info} from '@flow-step/step-toolkit'
import * as fs from 'fs'
import { IGitSourceParams } from './git-source-params'
import * as util from './util'

export class SvnSource {
    async handleSvnSource(sourceParams: IGitSourceParams) {
        const checkoutResult = await this.updateOrCheckoutSvnRepo(sourceParams)
        if(checkoutResult != 0) {
            return checkoutResult
        }
        return await this.writeSvnInfo(sourceParams)
    }

    async writeSvnInfo(sourceParams: IGitSourceParams) {
        const svnLogs: string[] = []
        let resultCode = -1
        if(sourceParams.svnCheckoutUrl.toString().startsWith("https")) {
            resultCode = await step.exec.call('svn', ['log', '--non-interactive', '--trust-server-cert-failures=unknown-ca,cn-mismatch,expired,not-yet-valid,other', '--username', `${sourceParams.user}`, `--password`, `${sourceParams.password}`, '-l', '1'], {
                cwd: sourceParams.svnCheckoutDirFull(),
                listener: {
                    stdoutLine: (line: string) => {
                        svnLogs.push(line)
                        step.info(line)
                    },
                    stderrLine: (line: string) => step.error(line),
                }
            })
        } else {
            resultCode = await step.exec.call('svn', ['log', '--username', `${sourceParams.user}`, `--password`, `${sourceParams.password}`, '-l', '1'], {
                cwd: sourceParams.svnCheckoutDirFull(),
                listener: {
                    stdoutLine: (line: string) => {
                        svnLogs.push(line)
                        step.info(line)
                    },
                    stderrLine: (line: string) => step.error(line),
                }
            })
        }

        if(resultCode != 0) {
            step.error("fail to collect svn commit info")
            return resultCode
        }

        const svnCommitVersion = svnLogs[1].split('|')[0].trim()
        const svnCommitAuthor = svnLogs[1].split('|')[1].trim()
        const svnCommitTime = svnLogs[1].split('|')[2].trim()

        const linesStr = svnLogs[1].split('|').pop()!.trim().split(' ')[0]
        const lines = parseInt(linesStr)

        const svnCommitMsg = svnLogs.slice(3, 3 + lines).join('')
        const svnCommitMsgKey = `${sourceParams.repo}.${sourceParams.svnCheckoutDir()}.commitMsg`

        step.addOutput(`${svnCommitMsgKey}=[{"commitTime":"${svnCommitTime}", "commitMsg":"${svnCommitMsg}", "commitId":"${svnCommitVersion}", "commitAuthor":"${svnCommitAuthor}"}]`)
        step.addOutput(`outputsToEnv.CI_SOURCE_NAME=${sourceParams.svnRepoName()}`)

        step.addOutput(`outputsToEnv.CI_SOURCE_NAME_${sourceParams.order}=${sourceParams.svnRepoName()}`)
        step.addOutput(`outputsToEnv.CI_COMMIT_ID=${svnCommitVersion}`)
        step.addOutput(`outputsToEnv.CI_COMMIT_ID_${sourceParams.order}=${svnCommitVersion}`)
        step.addOutput(`outputsToEnv.CI_COMMIT_REF_NAME=${sourceParams.branch}`)
        step.addOutput(`outputsToEnv.CI_COMMIT_REF_NAME_${sourceParams.order}=${sourceParams.branch}`)
        step.addOutput(`outputsToEnv.CI_COMMIT_TITLE=${svnCommitMsg}`)
        step.addOutput(`outputsToEnv.CI_COMMIT_TITLE_${sourceParams.order}=${svnCommitMsg}`)
        step.exportEnvVar('CI_SOURCE_NAME', sourceParams.svnRepoName())
        step.exportEnvVar(`CI_SOURCE_NAME_${sourceParams.order}`, sourceParams.svnRepoName())
        step.exportEnvVar('CI_COMMIT_ID', svnCommitVersion)
        step.exportEnvVar(`CI_COMMIT_ID_${sourceParams.order}`, svnCommitVersion)
        step.exportEnvVar(`CI_COMMIT_REF_NAME`, sourceParams.branch!)
        step.exportEnvVar(`CI_COMMIT_REF_NAME_${sourceParams.order}`, sourceParams.branch!)
        step.exportEnvVar('CI_COMMIT_TITLE', svnCommitMsg)
        step.exportEnvVar(`CI_COMMIT_TITLE_${sourceParams.order}`, svnCommitMsg)
        return 0
    }

    async updateOrCheckoutSvnRepo(sourceParams: IGitSourceParams) {
        if(fs.existsSync(`${sourceParams.svnCheckoutDirFull()}/.svn`)) {
            if((await this.updateSvnRepo(sourceParams)) == 0) {
                return 0
            }
        }
        return await this.checkoutSvnRepo(sourceParams)
    }

    async updateSvnRepo(sourceParams: IGitSourceParams) {
        info(`svn update ${sourceParams.repo}/${sourceParams.branch} to ${sourceParams.svnCheckoutDir()}`)
        let resultCode = -1
        if(sourceParams.svnCheckoutUrl.toString().startsWith("https")) {
            resultCode = await step.exec.call('svn', ['update', '--trust-server-cert-failures=unknown-ca,cn-mismatch,expired,not-yet-valid,other', '--non-interactive', '--username', `${sourceParams.user}`, `--password`, `${sourceParams.password}`], {
                cwd: sourceParams.svnCheckoutDirFull(),
                listener: {
                    stdoutLine: (line: string) => step.info(line),
                    stderrLine: (line: string) => step.error(line),
                }
            })
        } else {
            resultCode = await step.exec.call('svn', ['update', '--username', `${sourceParams.user}`, `--password`, `${sourceParams.password}`], {
                cwd: sourceParams.svnCheckoutDirFull(),
                listener: {
                    stdoutLine: (line: string) => step.info(line),
                    stderrLine: (line: string) => step.error(line),
                }
            })
        }

        if(resultCode != 0) {
            step.warning('svn update fail and re-checkout')
        } else {
            step.info("svn update success")
        }
        return resultCode
    }

    async checkoutSvnRepo(sourceParams: IGitSourceParams) {
        step.info('Clean up workspace')
        if (fs.existsSync(sourceParams.projectDir)) {
            util.clearDir(sourceParams.projectDir)
        } else {
            fs.mkdirSync(sourceParams.projectDir)
        }

        step.info(`svn checkout ${sourceParams.svnCheckoutUrl()} to ${sourceParams.svnCheckoutDir()}`)

        let resultCode = -1
        if(sourceParams.svnCheckoutUrl.toString().startsWith("https")) {
            resultCode = await step.exec.call('svn', ['checkout', '--trust-server-cert-failures=unknown-ca,cn-mismatch,expired,not-yet-valid,other', '--non-interactive', sourceParams.svnCheckoutUrl(), '--username', `${sourceParams.user}`, `--password`, `${sourceParams.password}`, '--no-auth-cache'], {
                cwd: sourceParams.projectDir,
                listener: {
                    stdoutLine: (line: string) => step.info(line),
                    stderrLine: (line: string) => step.error(line),
                }
            })
        } else {
            resultCode = await step.exec.call('svn', ['checkout', sourceParams.svnCheckoutUrl(), '--username', `${sourceParams.user}`, `--password`, `${sourceParams.password}`, '--no-auth-cache'], {
                cwd: sourceParams.projectDir,
                listener: {
                    stdoutLine: (line: string) => step.info(line),
                    stderrLine: (line: string) => step.error(line),
                }
            })
        }

        if(resultCode != 0) {
            step.error('svn checkout error')
        } else {
            step.info('svn checkout success')
        }
        return resultCode
    }
}
